import org.lwjgl.opengl.GL11;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.Arrays;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

public class Box {
    
    private int FRAMENANOS = 0;
    private float couf = 0;
    private float coug = 0;
    ///
    	//movement stuff
    	private int Xoff = 4;
    	private int Yoff = 1;
    ///
    private ArrayList<VBOobject> VAOs = new ArrayList<VBOobject>();
    private ArrayList<RenderObject> ROs = new ArrayList<RenderObject>();
    
    private double rotate_x, rotate_y, rotate_z;
    private float[] theMatrix;
    

    /// shader
    private shader Shader;
	//create the vertex array

    
    public Box(int FRAMENANOS1){
    	FRAMENANOS = FRAMENANOS1;
    	Shader = new shader();
    	Yoff = Yoff + 0;
    	calculateMatrix();
    }
    private void calculateMatrix(){
    	float fFrustumScale = 1.0f; float fzNear = 0.1f; float fzFar = 4.0f;

    	theMatrix = new float[16];
    	Arrays.fill(theMatrix, 0);

    	theMatrix[0] = fFrustumScale;
    	theMatrix[5] = fFrustumScale;
    	theMatrix[10] = (fzFar + fzNear) / (fzNear - fzFar);
    	theMatrix[14] = (2 * fzFar * fzNear) / (fzNear - fzFar);
    	theMatrix[11] = -1.0f;

    	
    }
    /*
    * If the shader was setup succesfully, we use the shader. Otherwise
    * we run normal drawing code.
    */
    public void draw(int delta1, long time){
    	float delta = delta1;
    	delta  = delta / FRAMENANOS;
    	couf+=(0.01*delta);
    	coug+=(1.0f*delta);
    	if(Shader.enabled()){
    		
    		
    		GL20.glUseProgram(Shader.TheShader());
    		Shader.setUniformMatrix("perspectiveMatrix",theMatrix);
    		//Shader.setUniform("offset",coug);
    		Shader.setUniform("Zoffset",10.0f);
    		
    		
    	}

        // clear the display
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

        // perform rotation transformations
        GL11.glPushMatrix();

        rotate_x = ((double)time / 100000000.0) % 360.0;
        rotate_y = ((double)time / 50000000.0) % 360.0;
        rotate_z = ((double)time / 30000000.0) % 360.0;
        
        GL11.glTranslatef(0, 0, (-8.0f*(Xoff/4.0f)));
        float what = 1-(((float)Math.sin(couf)+1)/4);
       // GL11.glScalef(what, what, what);

        GL11.glRotated(
          rotate_x,
          1.0,
          0.0,
          0.0
        );
         
        GL11.glRotated(
          rotate_y,
          0.0,
          1.0,
          0.0
        );

        GL11.glRotated(
          rotate_z,
          0.0,
          0.0,
          1.0
        );
        
        //send the data to the gpu
        //

       //check for any errors
        int error = GL11.glGetError();
        if (error != 0) {
            System.out.println("OpenGL error '" + error + "' occured!");
        }
        
        if (!ROs.isEmpty()){
	   		 for(int i=0; i<ROs.size(); i++){
	             if (ROs.get(i) != null){
	            	 //load the correct VBO
	            	 GL30.glBindVertexArray(VAOs.get(ROs.get(i).getVBOo()).getVao());
	            	 //RENDER//
	            	 GL11.glDrawElements(VAOs.get(ROs.get(i).getVBOo()).getMode(), VAOs.get(ROs.get(i).getVBOo()).getIndices().length, GL11.GL_UNSIGNED_SHORT, 0);
	             }
	        }	
        }
        

        // restore the matrix to pre-transformation values
        GL11.glPopMatrix();        
        GL20.glUseProgram(0);
        
    }
    public int InitializeVertexBuffer(float vertexPositions[],  short[] indices){
    	//create float buffer and populate it
    	FloatBuffer Fbuf = BufferUtils.createFloatBuffer(vertexPositions.length);
    	Fbuf.put(vertexPositions);
    	Fbuf.rewind();
    	//Create index data
        ShortBuffer indexData = BufferUtils.createShortBuffer(indices.length);
        indexData.put(indices);
        indexData.flip();
        //Buffer creation and loading
        int vertexBuffer = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vertexBuffer);
        GL15.glBufferData(GL15.GL_ARRAY_BUFFER, Fbuf, GL15.GL_STATIC_DRAW);
        int indexBuffer = GL15.glGenBuffers();
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
        GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indexData, GL15.GL_STATIC_DRAW);
        //Start Building the VAO
        int vao = -1;
        vao = GL30.glGenVertexArrays();
        GL30.glBindVertexArray(vao);
        
        int location = GL20.glGetAttribLocation(Shader.TheShader(), "inVertex");
    	GL20.glEnableVertexAttribArray(location);
    	GL20.glVertexAttribPointer(location, 3, GL11.GL_FLOAT, false, 28, 0);
    	
    	location = GL20.glGetAttribLocation(Shader.TheShader(), "inColor");
        GL20.glEnableVertexAttribArray(location);
        GL20.glVertexAttribPointer(location, 4, GL11.GL_FLOAT, false, 28, 12);

        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
      
        GL30.glBindVertexArray(0); //Unbind 
        //Building complete
        if (vao == -1){
        	System.err.println("VAO BUILDING FAILURE");
        }
        return vao;
    }
    
    public void inputhand(int string){
	    	switch (string) {
	        case 1:  Xoff ++;
	        break;
	        case 2:  Xoff --;
	        break;
	        case 3:  Yoff ++;
	        break;
	        case 4:  Yoff --;
	        break;
	        case 5:  printlog();
	        break;
	    	}
    	}
    		
    private void printlog() {
    	System.out.println("\n -- Printing log --");
		 for(int i=0; i<VAOs.size(); i++){
             if (VAOs.get(i) != null){
            	 System.out.print("VAOs position #"+i+"\t");
            	 System.out.print("Type: "+VAOs.get(i).getType()+"\t");
            	 System.out.print("Indices Length: "+VAOs.get(i).getIndices().length+"\t");
            	 System.out.print("VertexPositions Length: "+VAOs.get(i).getVertexPositions().length+"\t");
            	 System.out.print("VBO: "+VAOs.get(i).getVao()+"\t");
            	 System.out.print("\n");
             }
        }
		System.out.print("-ROs--\n");
        if (!ROs.isEmpty()){
	   		 for(int i=0; i<ROs.size(); i++){
	             if (ROs.get(i) != null){
	            	System.out.print("ROs position #"+i+"\t");
	            	System.out.print("VBOo Ref: "+ROs.get(i).getVBOo()+"\t");
	            	System.out.print("Render: "+ROs.get(i).render+"\t");
	            	System.out.print("\n");
	             }
	        }	
        }else{
        	 System.out.print("Empty");
        }
    	
    	 
        System.out.print("\n -----\n");
	}

	

	public int GetVBO(String type) {
		//do we have a vbo for that type?
		boolean found = false;
		int i;
		 for(i=0; i<VAOs.size(); i++){
             if (VAOs.get(i) != null){
            	 if (VAOs.get(i).getType().equals(type)){
            		 found = true;
            		 break;
            	 }
             }
        }
		//System.out.println("Looking for : " + type+" , Found = "+found);	
		if(found){
			
			
		}else{
			//we need to create a new VBOo
			VBOobject pyro1 = new VBOobject(type);
			//is everything ok ion there?
				if (pyro1.isSafe() == false){
					System.out.println("PROBLEM with creating VBOo:"+type);	
					return -1;}
			//generate a vao for it
			int vao = InitializeVertexBuffer(pyro1.getVertexPositions(), pyro1.getIndices());
			pyro1.setVbo(vao);
			//add to index
			VAOs.add(pyro1);
		}
		return i;
	}

	public int addObject(int VBOobjectRef) {
		RenderObject Ro = new RenderObject(VBOobjectRef);
		ROs.add(Ro);
		return ROs.indexOf(Ro);
	}
	public RenderObject getObject(int RenderRef) {
		return ROs.get(RenderRef);
	}

}







